import numpy as np 
import cv2 as cv 
import os


###PCA with covariance
def pca_cov(X, contribution=.95):
    '''
    input X, and contribution
    return the result of dimensionality reduction and mean of raw data and eigen values
    
    '''
    N, P = X.shape
    #do the centralization for x
    x_head = 1/N * X.T.dot(np.ones((N, 1)))
    X = X - x_head.T
    
    #get the coariance of X
    #centering matrix I(N*N) - 1/N * 1N * 1N.T
    H = np.identity(N) - 1/N * np.dot(np.ones((N, 1)), np.ones((1, N)))
    #Covariance matrix
    cov_mat = 1/N * X.T.dot(H).dot(X)
    #get eigenVetor & eigenValue
    eig_val, eig_vector = np.linalg.eig(cov_mat)
    #get eig_vetor which contribute over 90%(default)
    eig_val = np.sort(eig_val)[::-1]
    eig_val_percent = np.cumsum(eig_val) / eig_val.sum()
    #return the top k value contribute the 90%(default) of eigen values
    k = np.argwhere(eig_val_percent > contribution)[0][0]
    #get top k's index
    top_k_index = np.argsort(eig_val)[-k:]
    #get the eigen values of the top k eigine vetor
    eig_vector = eig_vector[:, top_k_index]
    #data after dimensionality reduction
    X_reduction = X.dot(eig_vector) 
    
    return X_reduction, x_head, eig_vector
    

def map_data(X, x_head, eig_vector):
    '''
    map data to the raw space
    input:
        X, the data after dimensionality reduction
        x_head, x mean of the raw data
        eig_val, the eigen values of the covriance
    return:
        data mapping to the raw space
    '''
    #here, cause the covriance is symmery matrix. so eig_val * eig_val.T = I
    return X.dot(eig_vector.T) + x_head

#look pca from perspective of svd
# S = X.T * H.T * H * X
#H*X(centralization of x) = U kesi V.T （奇异值分解）
#
# v = eigen vetor, kesi^2 = egien value
def pcoa(X):
    N, P = X.shape
    H = np.identity(N) - 1/N * np.dot(np.ones((N, 1)), np.ones((1, N)))
    u, s, v = np.linalg.svd(H.dot(X))
    S = np.zeros((225, 225))
    for i in range(225):
        S[i][i] = s[i]
    
    PCoa = u.dot(S)
    return u.dot(s)
    
    

if __name__ == '__main__':
    image_name = os.path.join(os.getcwd(), 'geeks14.png')
    image = cv.imread(image_name)
    image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    pca, x_head, eig_vector = pca_cov(image, .99)
    
    mapping = map_data(pca, x_head, eig_vector)
    mapping = mapping.astype(np.uint8)
    
    cv.imshow('res', mapping)


    
    
